// import { Grid } from "./grid";
// import { Tile } from "./tile";
import { Grid } from "./grid";
import levelsData from "./level.json";
import { Shooter } from "./shooter";
import { Tile } from "./tile";
import * as TWEEN from '@tweenjs/tween.js';

/*
  1.设置关卡level数据,初始化泡泡布局和弹药
  2.发射新泡泡,泡泡会根据盒子边界进行反弹,绘制反弹
  3.泡泡移动过程中，检测碰撞
  4.泡泡碰撞后，计算停靠位置，更新泡泡布局，更新可用颜色集合
  5.停靠之后,判断消除,判断下落,更新分数
  6.判断游戏结束,更新游戏存储
*/

interface LevelObject {
  map?: any[]; // 游戏地图布局，二维数组，每个元素代表地图上一个位置的对象（数字或字符串）
  armo?: number; // 弹药数量，可选属性
}

type LevelDataType = {
  [key: string]: LevelObject;
};

const levelData: LevelDataType = levelsData;

export class GameManager {
  storageManager: any;
  actuator: any;
  colourSet: any[] = ["yellow", "purple", "green", "red", "blue"];//当前5种颜色集合
  levelStat: LevelObject = {};//当前关卡的统计信息
  armo: number = 5;// 弹药数量，目前场上泡泡颜色随机
  map: any[] = [];//游戏地图布局
  level: number = 13;//当前关卡
  gravity: number = 1e3;//游戏重力
  shooter: any;//射击器
  grid: any; // 游戏网格存泡泡布局
  over: any; // 游戏是否结束
  score: number = 0; //最终得分
  scoreMap: any = {
    "3": 10,
    "4": 15,
    "5": 20,
    "6": 25,
    "7": 30,
    "8": 35,
    "9": 40,
    "10": 45,
    "11": 50,
    "12": 55,
  };//得分表
  R = 15; // 泡泡半径
  size = this.R * 2; // 泡泡直径
  yd = Math.sqrt(3) * this.R; // (Math.sqrt(3) / 2) * (2 * this.R)六边形排列中的,两个相邻泡泡的垂直间距
  speed = this.R; // 速度 沿着路线移动的速度,影响碰撞检测的精度
  W = 0; // 游戏面板宽度
  maxRow = 10;// 最大行数
  maxCol = 11;// 最大列数,每行最大泡泡数量,偶数比奇数少一个
  bufferRow = 6; //缓存行
  boxRow = this.maxRow + this.bufferRow;// box的行数
  maxTop = 0; // 最大高度 ?
  maxX = 0; // 最大left
  maxY = 0; // 最大top
  boxClientRect: any; // 游戏面板的 DOM 元素的边界信息
  tween: any = null; // 缓动对象
  animatieId: any = null;//动画id
  isAnimating: boolean = false;//是否正在动画中
  newPao: any = null;//当前泡泡
  private shootPaoQueue: { start: { radian: number, cl: number, ct: number } }[] = []
  // 标记是否正在处理队列
  private isProcessingQueue: boolean = false
  private isModifyingGrid: boolean = false; //修改网格时加锁
  lastTopCellPosition: any = null; // 最靠下单元格位置


  constructor(actuator: any, storage: any) {
    this.storageManager = storage;
    this.actuator = actuator;

    const box = document.getElementById("game-box");
    this.boxClientRect = box?.getBoundingClientRect();
    this.W = box?.clientWidth || 0;
    this.maxTop = (box?.clientHeight || 0) - this.R * 2 * 2;
    this.maxX = this.W - this.size;
    this.maxY = this.maxTop - this.size;

    this.shooter = new Shooter();
    this.shooter.on("shoot", this.shootPao.bind(this));//将 GameManager 类的 move 方法绑定到 inputManager 对象的 "move" 事件上
    this.shooter.on("line", this.drawLine.bind(this));

    this.setup();
    // this.drawLine({ radian: 0.3181051640486569, cl: 164, ct: 595.546875 });
  }

  // Restart the game
  restart() {
    this.storageManager.clearGameState();
    this.setup();
  }
  setup() {
    const previousState = this.storageManager.getGameState();

    if (previousState) {
      console.log(previousState);
      this.grid = new Grid(previousState.grid.map, this.colourSet, this.maxRow, this.maxCol, this.boxRow); // Reload grid
      this.armo = previousState.armo;
      this.level = previousState.level;
      this.over = previousState.over;
      this.score = previousState.score;
      this.boxRow = previousState.boxRow;
    } else {
      this.levelStat = levelData[`lvl${this.level}`]
      this.armo = this.levelStat.armo || 10;
      this.map = this.levelStat.map || [];
      this.grid = new Grid(this.map, this.colourSet, this.maxRow, this.maxCol, this.boxRow); // 初始化网格
      console.log('levelStat', this.colourSet, this.map, this.grid);
      this.over = false;
    }

    this.actuate();
  }
  // 更新页面和持久化状态
  async actuate() {
    const girfInfo = this.grid?.serialize();
    this.map = girfInfo.map; // 更新网格中 map
    this.isOver();// 检查游戏是否结束
    if (this.over) {
      this.storageManager.clearGameState();
    } else {
      const state = {
        grid: girfInfo,
        score: this.score,
        over: this.over,
        armo: this.armo,
        level: this.level,
        boxRow: this.boxRow,
      }
      this.storageManager.setGameState(state);
    }

    const boxHeight = this.boxRow * this.yd + this.size
    await this.actuator.actuate({ grid: girfInfo, score: this.score, over: this.over, boxHeight })
    if (!this.over) {
      this.addShooter();
    }

  }
  isOver(exit?: boolean) {
    // ①主动退出 ②消除完毕或弹药用尽
    if (exit || this.armo <= 0 || !this.grid.occupiedCells().length) {
      this.over = true;
      this.score = this.score + this.armo * 200;//剩余泡泡数量*200分
    }
  }
  addShooter() {
    const color = this.grid.getRandomColor()
    // const color = "blue";
    const middleCol = Math.floor((this.maxCol - 1) / 2);
    this.newPao = new Tile({ x: this.boxRow, y: middleCol }, color); //在box正下方的索引
    this.actuator.addTile(this.newPao);
    this.newPao.updateStylePosition({ l: this.W / 2 - this.size / 2, t: this.newPao.t });
    this.actuator.updateTileStylePosition(this.newPao);
    this.armo--;
    console.log('新的泡泡', this.newPao);
  }
  async shootPao(start: { radian: number, cl: number, ct: number }) {
    // 将请求添加到队列中
    this.shootPaoQueue.push({ start })
    // 如果当前没有在处理队列，则开始处理
    if (!this.isProcessingQueue) {
      await this.shoot()
    }
  }
  private async shoot() {
    if (this.over) return;
    this.isProcessingQueue = true
    try {
      console.log('😀GameManager shootPao', this.armo);
      while (this.shootPaoQueue.length > 0) {
        const { start } = this.shootPaoQueue.shift()!
        this.actuator.clearLine();
        //1、通过发射角度,计算反弹路径,返回碰撞点
        const path: any[] = this.searchPath(start)
        //2、执行发射动画,停靠到合适位置
        await this.moveByPath(path)
        this.grid.updateGrid(this.map, this.newPao, this.boxRow);
        console.log(this.newPao, this.maxRow, this.boxRow, this.grid.cells);
        // 3、检查是否消除
        const removedPaos = this.searchRemovePaos(this.newPao)
        if (removedPaos.length) {
          await this.toRemove(removedPaos)
          // 4、检查是否下落
          const dropPaos = this.searchDropPaos();
          if (dropPaos.length) await this.toDrop(dropPaos);
        }
        const lastCell = this.grid.lastCellContent();
        if (lastCell) {
          console.log('调整前', lastCell, this.lastTopCellPosition, this.maxRow, this.boxRow, this.grid.cells);
          if (lastCell.x >= this.maxRow - 1) {
            console.log('页面向上移动');
            //超出最大行数，页面向上移动
            this.boxRow = this.boxRow + 1
            this.maxRow = this.maxRow + 1;
            const boxHeight = this.boxRow * this.yd + this.size
            await this.actuator.upTileContainer(boxHeight)
            this.lastTopCellPosition = lastCell;
          }

          if (this.lastTopCellPosition && lastCell.x < this.lastTopCellPosition.x) {
            //页面向下移动
            console.log('页面向下移动');
            this.maxRow = lastCell.x + 1 < 10 ? 10 : lastCell.x + 1;
            this.boxRow = this.maxRow + this.bufferRow; //this.boxRow - this.bufferRow=this.maxRow
            const boxHeight = this.boxRow * this.yd + this.size
            await this.actuator.upTileContainer(boxHeight)
            this.lastTopCellPosition = lastCell;
          }
        }
        console.log('调整后', this.maxRow, this.boxRow, this.grid.cells);
        await this.actuate();
        // 处理完队列后标记为未处理状态
        this.isProcessingQueue = false
      }
    } catch (error) {
      console.error("处理队列时出现异常:", error)
    }
  }
  //计算泡泡路径，渲染辅助线
  searchPath(startPoint: { radian: number, cl: number, ct: number }) {
    // l, t：当前点屏幕坐标，dis：从上一个点到该点的距离，hl, ht：被碰撞的泡泡
    const path: { l: number, t: number, dis?: number, hl?: number, ht?: number }[] = [{ l: startPoint.cl, t: startPoint.ct }];
    let tg: { l: number, t: number, dis: number, hl: number, ht: number }[] = [];
    let nextPoint: { radian: number, cl: number, ct: number } = startPoint;
    let d = 0; // 距离,三角函数里的斜边
    // this.drawPoint(startPoint)
    // this.drawPoint({ cl: this.maxX, ct: this.maxY }, 'green')
    while (1) {//开启无限循环
      // 计算下一个点的坐标
      nextPoint.cl = nextPoint.cl + this.speed * Math.cos(nextPoint.radian);
      nextPoint.ct = nextPoint.ct - this.speed * Math.sin(nextPoint.radian); // y轴取反，向上移动
      // console.log('startPoint', startPoint);
      // console.log('nextPoint', nextPoint);
      // this.drawPoint(nextPoint)
      if (nextPoint.cl <= 0) {
        // 左边界
        nextPoint.cl = 0;
        // 三角函数：Math.cos(angleX)=l/d,Math.sin(angleX)=t/d
        d = Math.abs(path[path.length - 1].l / Math.cos(nextPoint.radian));
        nextPoint.ct = path[path.length - 1].t - d * Math.sin(nextPoint.radian);// y轴取反，向上移动
        if (nextPoint.ct < 0) nextPoint.ct = 0;
        path.push({ l: nextPoint.cl, t: nextPoint.ct, dis: d });
        if (nextPoint.ct == 0) break;
        // 反弹:左边界法线是x轴正方向，反射角度= -π -入射角度
        nextPoint.radian = -Math.PI - nextPoint.radian;
        // const colIndex = Math.floor(nextPoint.cl / this.size);//当前泡泡坐标,用于查找相邻泡泡
        // const rowIndex = Math.floor(nextPoint.ct / this.yd);
        // console.log('碰到左边界', nextPoint, rowIndex, colIndex, path);
        // continue;//跳过后续代码，回到循环开头
      } else if (nextPoint.cl >= this.maxX) {
        //右边界
        nextPoint.cl = this.maxX;
        d = Math.abs((nextPoint.cl - path[path.length - 1].l) / Math.cos(nextPoint.radian));
        nextPoint.ct = path[path.length - 1].t - d * Math.sin(nextPoint.radian);// y轴取反，向上移动
        if (nextPoint.ct < 0) nextPoint.ct = 0;
        path.push({ l: nextPoint.cl, t: nextPoint.ct, dis: d });
        if (nextPoint.ct == 0) break;
        // 反弹:右边界法线是x轴负方向，反射角度= π -入射角度
        nextPoint.radian = Math.PI - nextPoint.radian;
        // const colIndex = Math.floor(nextPoint.cl / this.size);//当前泡泡坐标,用于查找相邻泡泡
        // const rowIndex = Math.floor(nextPoint.ct / this.yd);
        // console.log('碰到右边界', nextPoint, rowIndex, colIndex, path);
        // continue;//跳过后续代码，回到循环开头
      }

      if (nextPoint.ct < 0) nextPoint.ct = 0; //顶部边界，防止泡泡飞出游戏面板上方
      if (nextPoint.ct < this.maxTop) {
        //最大高度边界内部
        const colIndex = Math.floor(nextPoint.cl / this.size);//当前泡泡坐标,用于查找相邻泡泡
        const rowIndex = Math.floor(nextPoint.ct / this.yd);
        const positionsToCheck: { x: number, y: number, info: string }[] = this.getNeighborsPositions(rowIndex, colIndex); //检查六边形位置
        // console.log('碰撞检测的所有位置+++++++++++++++', positionsToCheck);
        for (const position of positionsToCheck) {
          tg = tg.concat(this.checkHit(nextPoint, position));
        }

        // 如果有多个碰撞点，取最近的一个
        if (tg.length > 0) {
          if (tg.length > 1)
            tg.sort(function (a, b) {
              return a.dis - b.dis;
            });
          path.push({ l: tg[0].l, t: tg[0].t, hl: tg[0].hl, ht: tg[0].ht, dis: tg[0].dis });
          // console.log('如果有多个碰撞点，取最近的一个', tg, path);
          break;
        }
      }
      if (nextPoint.ct == 0) {
        // 顶部边界
        nextPoint.cl = (Math.floor(nextPoint.cl / this.size) + (nextPoint.cl % this.size > this.R ? 1 : 0)) * this.size;
        d = Math.abs((nextPoint.ct - path[path.length - 1].t) / Math.sin(nextPoint.radian));
        path.push({ l: nextPoint.cl, t: nextPoint.ct, dis: d });
        // console.log('碰到顶部边界');
        break;
      }
    }
    return path;
  }
  // 碰撞检测
  checkHit(nextPoint: { radian: number, cl: number, ct: number }, paoPosition: { x: number, y: number }) {
    let tg: { l: number, t: number, dis: number, hl: number, ht: number }[] = [];// 所有可能碰撞点,hl,ht:碰撞点屏幕坐标
    const cell = this.grid.cellContent(paoPosition);
    if (cell) {
      const dx = cell.l - nextPoint.cl;
      const dy = (cell.t - nextPoint.ct) * 2 / Math.sqrt(3); // 根据六边形调整 Y 轴比例
      const d = Math.sqrt(dx * dx + dy * dy);
      // console.log(paoPosition, nextPoint, cell, d);
      if (d <= this.size) { //检测两个小球之间的距离是否小于等于小球直径,影响碰撞检测的精度
        // this.drawPoint({ cl: cell.l, ct: cell.t }, 'pink')
        tg.push({ l: nextPoint.cl, t: nextPoint.ct, dis: d, hl: cell.l, ht: cell.t });
      }
    }
    return tg
  }
  moveByPath(path: any[]) {
    console.log('moveByPath--------------------------', path);
    // const test = this.drawPoint({ cl: path[0].l, ct: path[0].t }, 'pink')
    return new Promise(async (resolve) => {
      const playSegment = (index: number) => {
        if (index >= path.length - 1) {
          const np = this.newPaoPosition(path) //计算停靠位置
          this.newPao.updatePosition(np);
          this.actuator.updateTileStylePosition(this.newPao);
          console.log('移动结束,计算停靠位置', np);
          // 动画结束，停止循环
          this.stopAnimationLoop();
          resolve(1);
          return;
        }

        const start = path[index];
        const end = path[index + 1];

        this.tween = new TWEEN.Tween(start)
          .to(end, 200) // 动画持续时间 200ms
          .easing(TWEEN.Easing.Quadratic.Out) // 使用缓动函数
          .onUpdate(() => {
            // 更新泡泡位置
            this.newPao.updateStylePosition({ l: start.l, t: start.t });
            this.actuator.updateTileStylePosition(this.newPao);
          })
          .onComplete(() => {
            playSegment(index + 1); // 下一段动画
          })
          .start();

        this.startAnimationLoop(); // 确保动画循环已启动
      }
      playSegment(0);
    })
  }
  // 计算泡泡停靠位置,返回一个 不与已有泡泡重叠、不穿过泡泡、符合边界条件的最终吸附位置
  newPaoPosition(path: any[]) {
    const hitPoint = path[path.length - 1];
    // 在检测碰撞的时候, 路径上每一帧泡泡通过speed计算, 有时会"穿过"某个泡泡, 所以需要执行回退操作, 再检测碰撞直到不发生碰撞为止
    // 根据碰撞点坐标计算最接近的行号和列号
    // this.drawPoint({ cl: hitPoint.l, ct: hitPoint.t }, 'pink')
    // this.drawPoint({ cl: hitPoint.hl, ct: hitPoint.ht }, 'rgba(0, 0, 0, 0.5)')
    let finalRow = Math.floor(hitPoint.ht / this.yd);
    let finalCol = Math.floor(hitPoint.hl / this.size);
    const neighbors = this.getNeighborsPositions(finalRow, finalCol);
    for (const neighbor of neighbors) {
      if (neighbor.x > finalRow && !this.grid.cellContent({ x: neighbor.x, y: neighbor.y })) {
        finalRow = neighbor.x;
        finalCol = neighbor.y;
        console.log(`找到邻近空位 行:${finalRow}, 列:${finalCol}`);
        break;
      }
    }
    console.log(
      `碰撞点的行:${Math.floor(hitPoint.ht / this.yd)}, 列:${Math.floor(hitPoint.hl / this.size)} 最终 行:${finalRow}, 列:${finalCol}`
    );

    return { x: finalRow, y: finalCol }
  }
  // 查找所有相邻的同色泡泡,返回需要消除的泡泡
  searchRemovePaos(newPao: Tile): Tile[] {
    // 查找过程:以当前停靠的泡泡为起点，查看周围所有与它相邻的泡泡，如果发现周围有相同颜色（数字相同）的泡泡，那么就以这个泡泡为起点，继续查看其周围相邻的泡泡.....一直重复这个过程，直到周围不再有相邻的泡泡为止。
    // 记录所有相邻的泡泡,,以左上角泡泡为开始,顺时针进行查找相邻的泡泡
    const visited: Set<string> = new Set();//已访问集合,避免重复查找；
    const queue: Tile[] = [newPao]; //BFS 队列用于广度优先查找；
    const removePaos: Tile[] = [];// 存放最终要消除的泡泡；
    // 起始泡泡先加入
    visited.add(`${newPao.x},${newPao.y}`);
    removePaos.push(newPao);

    while (queue.length > 0) {
      const current = queue.pop();
      console.log('查找current', current);

      if (!current) continue;

      const neighbors = this.getNeighborsTiles(current);
      // console.log('相邻泡泡', neighbors);
      for (const neighbor of neighbors) {
        if (!neighbor) continue;
        const key = `${neighbor.x},${neighbor.y}`;
        // console.log('neighbor', neighbor, visited.has(key));
        if (visited.has(key)) continue; // 已经查过，跳过

        visited.add(key); // 标记为已访问

        if (neighbor.color === current.color) {
          removePaos.push(neighbor); // 同色泡泡加入消除列表
          queue.push(neighbor);      // 并继续扩散查找
        }
      }
    }

    return removePaos.length >= 3 ? removePaos : [];
  }
  async toRemove(removePaos: Tile[]) {
    if (this.isModifyingGrid) {
      console.warn("网格正在被修改，跳过本次消除");
      return;
    }
    this.isModifyingGrid = true;

    this.computeBaseScore(removePaos.length);
    const promises: any = [];
    removePaos.forEach((pao) => {
      // this.drawPoint({ cl: pao.l, ct: pao.t }, 'rgba(255, 192, 203,0.7)')
      this.grid.cells[pao.x][pao.y] = null;
      promises.push(this.actuator.removeTile(pao));
    })
    console.log("toRemove", removePaos);
    try {
      await Promise.all(promises);
    } finally {
      this.isModifyingGrid = false;
    }
  }
  searchDropPaos() {
    // 使用 BFS 思想查找所有“悬空”泡泡,返回值是所有掉落泡泡对象数组
    const visited: Set<string> = new Set();//用于记录已经访问过的泡泡
    const connectedToTop: Set<string> = new Set();// 存储和顶部相连的泡泡
    const queue: Tile[] = [];// BFS 队列

    // 初始化队列，将顶部的泡泡加入
    for (let y = 0; y < (0 % 2 === 0 ? this.maxCol : this.maxCol - 1); y++) {
      const topPao = this.grid.cells[0][y];
      if (topPao) {
        const key = `${0},${y}`;
        queue.push(topPao);
        visited.add(key);
        connectedToTop.add(key);
      }
    }

    // BFS 遍历
    while (queue.length > 0) {
      const current = queue.shift();
      if (!current) continue;

      const neighbors = this.getNeighborsTiles(current);
      for (const neighbor of neighbors) {
        if (!neighbor) continue;
        const key = `${neighbor.x},${neighbor.y}`;
        if (visited.has(key)) continue;

        visited.add(key);
        connectedToTop.add(key);
        queue.push(neighbor);
      }
    }

    // 遍历整个网格，找出所有未和顶部相连的泡泡
    const dropPaos: Tile[] = [];
    for (let x = 0; x < this.boxRow; x++) {
      const maxColInRow = x % 2 === 0 ? this.maxCol : this.maxCol - 1;
      for (let y = 0; y < maxColInRow; y++) {
        const pao = this.grid.cells?.[x]?.[y];
        if (pao) {
          const key = `${x},${y}`;
          if (!connectedToTop.has(key)) {
            dropPaos.push(pao);
          }
        }
      }
    }

    return dropPaos;
  }
  toDrop(dropPaos: Tile[]) {
    this.computeDropScore(dropPaos.length);
    const promises: any = [];
    dropPaos.forEach((pao) => {
      // this.drawPoint({ cl: pao.l, ct: pao.t }, 'rgba(255, 192, 203,0.7)')
      this.grid.cells[pao.x][pao.y] = null;
      const delay = Math.random() * 200;;
      promises.push(this.actuator.dropTile(pao, delay))
    })
    console.log("toDrop", dropPaos);
    return Promise.all(promises);
  }
  startAnimationLoop() {
    if (!this.isAnimating) {
      this.isAnimating = true;
      this.animatieId = requestAnimationFrame(this.animate.bind(this));
    }
  }
  stopAnimationLoop() {
    this.isAnimating = false;
    if (this.animatieId) {
      cancelAnimationFrame(this.animatieId);
      this.animatieId = null;
    }
  }
  animate(time: number) {
    if (this.isAnimating) {
      this.animatieId = requestAnimationFrame(this.animate.bind(this));
      this.tween?.update(time);
    }
  }
  drawPoint(point: { cl: number, ct: number }, color: string = "blue") {
    const container: any = document.getElementById('game-box');
    const newElement = document.createElement('div');
    newElement.style.position = 'absolute';
    newElement.style.left = `${point.cl}px`;
    newElement.style.top = `${point.ct}px`;
    newElement.style.width = this.size + 'px';
    newElement.style.height = this.size + 'px';
    newElement.style.backgroundColor = color;
    newElement.style.borderRadius = '50%';
    newElement.style.zIndex = '3';
    container.appendChild(newElement);
    return newElement
  }
  drawLine(start: { radian: number, cl: number, ct: number }) {
    const path: any[] = this.searchPath(start)
    // 测试反弹点位置
    // path.forEach((point) => {
    //   this.drawPoint({ cl: point.l, ct: point.t }, 'rgba(132, 141, 255, 0.3)')
    // })
    this.actuator.drawLine(path)
  }
  getNeighborsPositions(row: number, col: number) {
    const neighbors: { x: number, y: number, info: string }[] = [];
    const isEvenRow = (row % 2 === 0);
    // 定义6个相邻方向（六边形网格）
    // 顺序：左上、右上、右、右下、左下、左
    const directions = [
      { dx: -1, dy: isEvenRow ? -1 : 0, info: '左上' },
      { dx: -1, dy: isEvenRow ? 0 : 1, info: '右上' },
      { dx: 0, dy: 1, info: '右' },
      { dx: 1, dy: isEvenRow ? 0 : 1, info: '右下' },
      { dx: 1, dy: isEvenRow ? -1 : 0, info: '左下' },
      { dx: 0, dy: -1, info: '左' }
    ];
    // 按顺时针方向递归检查相邻泡泡
    for (const dir of directions) {
      const nx = row + dir.dx;
      const ny = col + dir.dy;
      // 边界检查
      if (
        nx < 0 || nx >= this.maxRow ||
        ny < 0 || ny >= (nx % 2 === 0 ? this.maxCol : this.maxCol - 1)
      ) {
        continue;
      }
      neighbors.push({ x: nx, y: ny, info: dir.info })
    }
    return neighbors
  }
  getNeighborsTiles(newPao: Tile): Tile[] {
    // 定义6个相邻方向（六边形网格）
    // 顺序：左上、右上、右、右下、左下、左
    const isEvenRow = (newPao.x % 2 === 0);
    const directions = [
      { dx: -1, dy: isEvenRow ? -1 : 0, info: '左上' },
      { dx: -1, dy: isEvenRow ? 0 : 1, info: '右上' },
      { dx: 0, dy: 1, info: '右' },
      { dx: 1, dy: isEvenRow ? 0 : 1, info: '右下' },
      { dx: 1, dy: isEvenRow ? -1 : 0, info: '左下' },
      { dx: 0, dy: -1, info: '左' }
    ];
    const neighbors = [];
    // 按顺时针方向递归检查相邻泡泡
    for (const dir of directions) {
      const nx = newPao.x + dir.dx;
      const ny = newPao.y + dir.dy;
      // 边界检查
      if (
        nx < 0 || nx >= this.maxRow ||
        ny < 0 || ny >= (nx % 2 === 0 ? this.maxCol : this.maxCol - 1)
      ) {
        continue;
      }
      const pao = this.grid.cells?.[nx]?.[ny];
      // console.log(`${nx}-${ny}-${dir.info}`, pao);
      if (pao) neighbors.push(pao)
    }
    return neighbors
  }
  computeBaseScore(count: number) {
    const scoreBase = this.scoreMap[count] ? this.scoreMap[count] : 55;//超出范围，默认55
    this.score = this.score + scoreBase * count;
  }
  computeDropScore(count: number) {
    this.score = this.score + 100 * count; //掉落的泡泡单价100
  }
  exitGame() {

  }
}